home *** CD-ROM | disk | FTP | other *** search
- .!****************************************************************************
- .!
- .! ANTIC PUBLISHING INC., COPYRIGHT 1985. REPRINTED BY PERMISSION.
- .!
- .! ** Professional GEM ** by Tim Oren
- .!
- .! Proff File by ST enthusiasts at
- .! Case Western Reserve University
- .! Cleveland, Ohio
- .! uucp : decvax!cwruecmp!bammi
- .! csnet: bammi@case
- .! arpa : bammi%case@csnet-relay
- .! compuserve: 71515,155
- .!
- .!****************************************************************************
- .!
- .!
- .!****************************************************************************
- .!
- .! Begin Part XVII
- .!
- .!****************************************************************************
- .!
- .PART XVII PC/ST Resource Converter
- .PP
- This the seventeenth installment of ST PRO GEM, the
- first to feature a complete GEM application. The program
- converts resource files between the ST (68000) and IBM PC
- (Intel) formats used by the respective versions of GEM and
- the Resource Construction Set.
- .PP
- The Resource Converter will, for the most part, be of
- direct use only if you are doing cross-development of GEM
- software on these two systems. In this case, you will want
- to read this entire article, starting with the "What It Does"
- heading. You may also be interested in an article on PC/ST
- conversion written by Mark Skapinker of Batteries Included,
- which appears in the Fall issue of START magazine (available
- September 1986).
- .PP
- If you are not doing cross machine development, you can
- still get something out of this column. Reading the program
- code and following the discussion, you will find practical
- examples of using GEM dialogs and following the internal
- structure of a resource file. Finally, there is a good deal
- of standard code for GEM initialization, AES utility
- functions, and GEMDOS file handling which you can extract for
- your own uses. If you fall in this category, skip the first
- parts of the column, and resume reading at the "How it Works"
- heading.
- .PP
- The download for this column is a set of source and
- binary files located on DL3 of the ATARI16 SIG, PCS-58. The
- files and their contents are:
-
- RCMAIN.C - Download and rename to RSCVMAIN.C
- This is the C source for main routine
- RCFILE.C - Download and rename to RSCVFILE.C
- This is the C source of GEMDOS utilities
- RCLIB.C - Download and rename to RSCVLIB.C
- C source of AES utility functions
- RSCONV.PRG - Linked binary of converter
- RSCONV.RSC - Binary resource image (ST format)
- RSCONV.DFN - Symbol file for resource (ST format for
- RCS 2.0)
- RSCONV.H - Object/tree name file for resource
- RLINK.SH - Download and rename to RSCVLINK.SH
- C-shell script for linking RSCONV
- SYLINK.SH - Download and rename to SYMLINK.SH
- Another script, used by RSCVLINK.SH
- .PP
- The final two files will be of use only if you are using Dave
- Beckemeyer's Micro C-Shell environment. If not, you can
- simply translate them to .BAT and/or .INP form for use with
- the Atari batch program and linker.
- .SH WHAT IT DOES
- A converter program is necessary because of the
- differing order of storage on the 68000 and Intel chips: the
- order of significance of bytes within words is reversed, as
- well as the order of words within long (32-bit) quantities.
- Attempting to load an unconverted resource on a GEM system
- with the other architecture will result in a crash, because
- all of the pointer and integer fields will be incorrect.
- .PP
- In addition, the format of symbol definition (DEF) files
- differs between the PC and ST implementations of the RCS in
- its first version. In the latest version from DRI, the
- formats do correspond, and the files now carry an extent name
- of DFN. However, the byte swapping problem must be corrected
- in either format for the symbols to be correctly loaded.
- As final touch, the converter also checks to be sure
- that a resource being loaded from the PC has its bit images
- synchronized to an even byte boundary. If this is not
- corrected, the ST will suffer a bus error when attempted to
- address the images with a word type operation, which will
- certainly happen in either the RCS or the application itself
- on the target system.
- .SH OPERATION
- When the Resource Converter loads, it presents an
- initial dialog box. (The converter does not use the menu
- bar.) The dialog has action buttons at the bottom labelled
- "Help", "Convert" and "Quit". Clicking the Help button will
- obtain a screen which summarizes these operating
- instructions. The Quit button terminates the program.
- Clicking Convert initiates the program's action, according to
- the options you have set in the rest of the dialog.
- .PP
- The top two buttons in the dialog establish the
- direction of the conversion. If you have built a resource on
- the PC and want to move it to the ST, click Intel->68000. If
- you are moving the file from the ST to the PC, click
- 68000->Intel.
- .PP
- The next two lines in the dialog establish the file
- extent names which will be used for the conversion. The
- input extent names are always on the left, no matter which
- conversion mode you selected above. By default, they are RSC
- and DEF. The output extents, on the right, are RS2 and DF2
- by default. The RSC/RS2 file extents are used for the
- resource, and DEF/DF2 extents are for the symbol file. Be
- careful that the input files you use are actually of the type
- (Intel or 68000) which you specified. If you get it
- backwards, the ST will most likely crash, though the input
- files will not be harmed.
- .PP
- The three buttons below the file extents determine the
- format of the input and output symbol files. If you click on
- DEF, the Resource Converter will assume that the input and
- output symbol files are in the old (that is, version 1.1)
- format used by the RCS. If you click on DFN, the program
- expects the new (version 2.0) symbol format. If the input
- symbol file extent is still set to "DEF", clicking this
- button will also change it appropriately. (Note that the DEF
- and DFN formats are in fact IDENTICAL on the PC ONLY. To
- "change formats" ON THE PC, you need only change the file's
- extent name, for example, rename FOOBAZ.DEF to FOOBAZ.DFN.
- On the ST, there is a real difference,and you must use the
- DRI DEF2DFN.PRG utility to go from old to new.)
- .PP
- The last button option is (OFF). Clicking this button
- disables the symbol file conversion. You may use this option
- to keep better control over versions of your resource. By
- establishing the main version on either the PC or ST, and
- converting only the resource file, not the symbols, you can
- ensure that no one will use the RCS on the destination
- machine to create a version which is different from the
- source.
- .PP
- When the Convert button is clicked to begin execution,
- the standard Item Selector is displayed. Use it to find and
- pick the input resource file which you want to convert. The
- Converter will use its main filename, substituting the
- various extents, to find the input definition file, and
- produce the output file names. If the definition file cannot
- be found in the same directory under the generated name, you
- will be presented with an alert, asking you to abort the
- conversion, continue without the symbol file, or specify a
- new name and/or directory for the file. If the output names
- coincide with existing files, they will be overwritten.
- .PP
- While the conversion operation is occurring, a progress
- indicator box will be displayed on the screen, with text
- messages indicating the current phase of the operation. When
- the conversion is complete, you are returned to the initial
- dialog, where you may quit or perform another conversion.
- .PP
- One last note on conversion, with a caution: it is
- possible to move files between Intel and 68000 even if you
- have two different versions of the Resource Construction Set,
- for instance, Version 2.0 on the PC and Version 1.1 on the
- ST. In this situation, you can take advantage of the
- identity between symbol file formats on the PC. Make a copy
- of the PC symbol file into another file with the DEF extent,
- and run the converter. The output should load on the ST
- version correctly. However, if you move symbols between
- different RCS versions, you MUST NOT use the "free strings"
- and "free images" features of version 2 and then move the
- symbols to version 1. Doing so may result in spurious
- assignment of the "free" symbols to trees and objects, and
- you will (of course) not be able to edit the free images
- and/or strings in the resource.
- .SH HOW IT WORKS
- For the ST-only developers now rejoining the discussion,
- I will now take a look at the standard GEM initialization
- code and the special dialog handling techniques which I have
- used in the Converter. Then we'll look at the guts of the
- code, which threads through the resource to do the actual
- conversion. For those interested in the supporting code
- libraries, the GEMDOS interface utilities in RSCVFILE.C were
- described in column number 15. The progress indicator
- functions of RCSLIB.C were detailed in column 16, and
- map_tree() and standard dialog handling techniques were
- discussed in columns three through five.
- .PP
- There are a number of useful facts in rscv_init(), the
- initialization code. First, notice that the result of
- appl_init is NOT assigned directly to gl_apid. Due to a bug
- in the appl_init binding the application ID is not returned
- as the function value. Instead it is returned to the global
- variable gl_apid. This bug wouldn't cause direct problems in
- the resource converter, but it will in any program which uses
- the ID when sending messages to its own pipe.
- .PP
- Next, an alert string to be displayed if the resource is
- not found has been explicitly included, to avoid a "Catch-22"
- situation. You can easily create such a string by building
- the alert in the RCS, using the C output option, and
- extracting the string from the resulting file.
- .PP
- Rscv_init() then sets up its VDI handle, by getting the
- physical workstation handle from graf_handle, and passing it
- to v_opnvwk (open virtual workstation), which returns the
- virtual workstation handle for use in VDI calls. V_opnvwk
- also returns the dimensions of the screen, which are copied
- to GRECT scrn_area, and the number of color planes, which is
- used to set up an MFDB for the screen: scrn_mfdb.
- .PP
- The wind_get call for the working area of the DESK
- window (number zero) results in the usable GRECT of the
- screen. This is different from scrn_area, because the menu
- bar's rectangle is reserved for the system.
- .PP
- You may want to take particular notice of the vst_height
- call, which reloads the character dimension variables. The
- values returned earlier by graf_handle are ALWAYS for the
- monochrome (high resolution) system font, and they are not
- appropriate for the low and medium resolution modes of the
- ST. Performing the vst_height call AFTER opening the virtual
- workstation will get the correct dimensions.
- .PP
- Some of the environment variables which are set up by
- rscv_init(), are not actually used in the resource converter.
- I have included them because they are part of my "generic"
- initialization procedures.
- .PP
- Finally, rscv_init() uses Malloc to reserve most of
- memory as a working buffer for the resource conversion.
- Notice that 4K are left free. You must leave at least 2K,
- and preferably a safety factor, or the AES will be unable to
- allocate memory for the file selector dialog, and your
- application will hang when calling fsel_input. By the way,
- an open virtual workstation uses about 8K, so you should do
- your Mallocs after the workstation call.
- .PP
- We now turn our attention to do_mode(), which handles
- the main dialog of the converter. After getting the root
- address of the dialog tree, the states of global variables
- conv_def and new_dfn are used to set up the radio button
- array for symbol file conversion. Native_in is used to set
- up the conversion type radio buttons. The last
- initialization step is to use the set_text() utility to link
- the file extent strings into the appropriate editable
- objects. Notice that this version of set_text() allows the
- string length to be explicitly supplied. For an editable
- text field object (G_FTEXT or G_FBOXTEXT), the length must be
- one greater than the number of blanks in the editing
- template.
- .PP
- Since there are TOUCHEXIT objects in the dialog, we
- cannot use the standard hndl_dial() routine. Instead, the
- form setup and draw calls are coded inline. The actual
- form_do call is placed inside a loop. If the object returned
- is not one of the TOUCHEXIT objects, the loop is terminated.
- .PP
- The two objects DEFYES and DFNYES, which select the old
- and new symbol file formats, respectively, have been made
- TOUCHEXIT. If either is clicked, the radio button processing
- is done by the AES, but then control is returned from
- form_do. Do_mode() then tests the current input symbol file
- extent. If it is "DEF" and we are switching from old to new
- mode, the extent is changed to "DFN". When switching from
- new to old mode, the reverse check is made. In either case,
- the disp_obj() utility is used to force an immediate redraw
- before returning to form_do for further user input.
- .PP
- When the loop terminates, do_mode() cleans up the screen
- with form_dial, and uses the selected() utility to retrieve
- the status of the radio button arrays and update the global
- variables. Finally, map_tree() is used to apply the
- deselection utility to all objects in the tree, leaving it
- clean for the next invocation of do_mode().
- .SH THE BELLY OF THE BEAST
- The routine dconv() contains the code for actually
- converting the resource. About half of do_conv() is devoted
- to accessing disk files, and correctly handling error
- conditions which might arise. The error recovery could
- perhaps be handled more concisely with artifices like
- "setjmp", but I have left it in-line for the sake of clarity.
- .PP
- Do_conv() also uses a collection of routines whose names
- begin with "swap_" Swap_bytes() and swap_words() are the
- workhorse routines. They simply run through a given area of
- memory, reversing every pair of bytes or words, respectively.
- (Remember that the word swapper will only work on even byte
- boundaries, or a bus fault will occur.) The other swap
- routines do the fix up for one type of resource structure
- each. I'll take apart a couple in detail, so that you can
- see the similarities in the others.
- .PP
- Now let's follow the do_conv() code. The first item of
- business is to use the get_file() utility, followed by
- open_file(), to find and open the input resource file.
- Again, you can see column 15 for a a discussion of these
- routines, which will handle DOS errors if they occur.
- .PP
- The Boolean conv_def is true if we need to open a
- symbols file. If everything goes right, just substituting a
- new extent name (from variable old_def), and doing the file
- open will get the file. If things foul up, do_conv() has to
- recover gracefully. So, it puts up the three button alert
- NODEF. The third button is an abort option; if it's picked
- we punt, closing the one open file and returning to the main
- dialog. Button one allows a continuation without the
- definition file (conv_def is forced FALSE so the user won't
- make the same mistake twice). Button two says try again, so
- get_file() is called to pick another file, and the whole
- process repeats.
- .PP
- Once the input file(s) are open, the operation will run
- to completion, assuming no disk errors. The mouse form is
- switched to an hour glass, and a progress indicator box is
- initialized on the screen.
- .PP
- The first action is to bring in the resource header
- only. If the resource is not native, that is, is not in
- 68000 format, its bytes must be swapped before using any of
- the counts and offsets. Note: if you've never dissected a
- resource before, this would be a good time take a look at the
- header format given in "gemdefs.h" in the Developer's Kit,
- and the resource structure definitions in "obdefs.h".
- .PP
- After the swap, if necessary, the resource size field
- can be used. Before reading the rest of the resource, the
- size must be compared against the size of the buffer
- allocated during initialization. If there isn't enough room,
- the NOMEM alert is displayed and control returns to the main
- dialog. (Since the biggest resource is 64K, and the
- Converter is rather small, this shouldn't ever happen. But,
- some people load up lots of desk accessories, so best to be
- prepared.)
- .PP
- After completing the resource input, an (admittedly
- kludgy) patch is made for the odd-byte-images problem. If
- the image offset pointer is odd, there will be problems on
- the ST. The fix made here relies on two facts. First, all
- images are an even number of bytes in size. Second, the old
- version of RCS DOES do an even byte synchronization AFTER
- writing the images. Therefore, if the images start on an odd
- byte, they will end on an even byte, and have one unused
- odd-addressed byte immediately following. The fixup strategy
- is to move all of the images up one byte, patch the offset in
- the header accordingly, and leave the img_odd flag set so
- that the bit image swap routine will also increment pointers
- in the BITBLK and ICONBLKs which use the images.
- .PP
- If the resource being converted is native, we can do the
- image fixup immediately. If not, all of the other swaps have
- to take first, because the long pointers in the BITBLKs and
- ICONBLKs are in the wrong order. (We don't have to swap
- string data; it's always stored in ascending order.)
- .PP
- Do_conv() calls subroutines to swap the tree index,
- objects, TEDINFOs, ICONBLKs, BITBLKs, and free string and
- images, in that order. We'll look at their actual code
- later. When this is finished, one of two cleanup actions is
- needed. If the resource WAS native, everything is now
- swapped except the header, which is finally reversed. If it
- used to be foreign (Intel), the pointers are now in proper
- 68000 order, so swap_images() can be called successfully.
- .PP
- Now it's time to write the converted resource, taking
- care that no error results. If no symbol file conversion is
- needed, do_conv() is done. The files are closed, the
- progress indicator completed, and control returns to
- rscv_run, which will set the cursor back to the arrow.
- Otherwise, it's time to handle the symbols file.
- .PP
- The first two bytes in the definition file are always
- the symbol count. They are read into nsym, and a scratch
- copy is made in reply, and swapped. Just which version is
- written to the output file depends on whether it is a DFN or
- DEF file. The new (DFN) format keeps a similar word order on
- both the ST and PC. For these files, the following code
- amounts to a verbatim copy.
- .PP
- Nsym is now used as the control variable of a loop which
- reads, converts, and writes one symbol entry on each
- iteration. In the old (DEF) file format, there was an extra
- word in the value field of each symbol's entry on the ST.
- Going from PC to ST, two padding zero bytes are added. Going
- the other way, they are read and discarded. For the old
- format, both the significant word of this field, as well as
- the following word field (the type) are swapped. The ten
- symbol bytes are passed through verbatim in both new and old
- format.
- .PP
- After swapping (old format) or simply copying (new
- format) of the symbol file is completed, file and progress
- box cleanup is done, and control returns.
- .SH THE OL' SWITCHEROO
- As promised, let's now go and look at a sampling of
- the structure swap routines: one of the simplest (tree
- index), one of medium complexity (objects), and the
- worst of the bunch (bit images).
- .PP
- Swap_trees() is responsible for fixing the tree index.
- Its location is found by adding an offset from the header
- (rsh_trindex) to the base address of the resource, stored in
- head. (Notice that head was defined as a byte pointer when
- the buffer was allocated, so I need to type coerce it to a
- resource header pointer before making structure references.)
- The number of trees is stored in the rsh_ntree header field.
- Each index entry is a long pointer of 32-bits, so the total
- size of the index may be found by multiplication. Finally,
- the swapping is done, first bytes within words, then words
- within the long pointers. (The order doesn't matter - work
- it out!)
- .PP
- Swap_objs() takes care of swapping fields inside of
- object structures. It begins similarly to swap_trees(),
- computing the base address of the objects from rsh_object,
- and taking the count from rsh_nobs. Since all of the objects
- are contiguous in a resource produced by RCS, and all fields
- of an object are words or longs, a byte swap is performed on
- the entire block at once. Now there are a couple of tricks.
- Notice that "where" in this routine is typed as an object
- pointer. As the number of objects is counted down in the
- loop, "where" is incremented. Because of its type, its
- actual pointer value will increase by sizeof(OBJECT) at each
- iteration. Inside the loop, only one long field, the
- ob_spec, needs to be word swapped. When the loop completes,
- all object structures are fixed.
- .PP
- Swap_fstr() and swap_fimg() use code similar to
- swap_trees(). The other resource structures, TEDINFOs,
- ICONBLKs, and BITBLKs, are transformed by code similar to
- swap_objs(). There is one subtlety here. These structures
- would normally be reaching by following an object's ob_spec
- pointer. To finesse a "swap now or later" ordering problem
- with the objects, I have instead used the resource header to
- find the structure arrays. You SHOULD NOT use this technique
- at run time, for two reasons. First, if you do any object
- patching on the fly, the correspondence between objects and
- reference strucutres will be destroyed. Second, there is no
- way to name a non-object structure with the RCS, and
- therefore no way to reliably retrieve it with rsrc_gaddr at
- execution time.
- .PP
- Last but not least, swap_images() not only takes care of
- switching bit image words, but also fixes image pointers as
- necessary if an odd byte problem has been detected. For
- these reasons, swap_images DOES follow pointers from the
- ICONBLKs and BITBLKs. The loop structure of the two sections
- of code will be familiar from swap_ibs() and swap_bbs().
- Size fields within the structure are used to determine the
- length of each image. If the img_odd flag has been set, the
- data pointer must be incremented BEFORE doing the swap, since
- the underlying data has already been moved.
- .SH PHEW!
- This column was deliberately long, in hopes that even
- those with no immediate use for this program will gain from
- the discussion. Do to space limits, the feedback is
- postponed to episode number 18, which will be another helping
- of "interface potpourri". Ingredients will include the popup
- menu code (finally), along with generic code for scrolling
- windows, and building your own scroll bars within dialogs.
- .!
- .!
- .!*****************************************************************************
- .!* *
- .!* End Part 17 *
- .!* *
- .!*****************************************************************************
-